﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;

namespace Reminder.Tests
{
    [TestClass]
    public class ReminderFixture
    {
        [TestMethod]
        public void CreateReminder()
        {
            TimeSpan emptyDuration = new TimeSpan(0);
            var newEmptyReminder = new Reminder(emptyDuration);
            StringAssert.Equals(string.Empty, newEmptyReminder.Message);
            StringAssert.Equals(string.Empty, newEmptyReminder.Name);

            Assert.IsNotNull(newEmptyReminder.TimeFromNow);
            Assert.AreEqual(newEmptyReminder.TimeFromNow, TimeSpan.MaxValue);
            Assert.IsFalse(newEmptyReminder.HasStarted);
            Assert.IsFalse(newEmptyReminder.HasExpired);

            /* Two param Constructor Option */
            const string TOMORROW = "Tomorrow";
            var reminder = new Reminder(TOMORROW, emptyDuration);
            StringAssert.Equals(TOMORROW, reminder.Message);
            StringAssert.Equals(string.Empty, reminder.Name);

            Assert.IsNotNull(reminder.TimeFromNow);
            Assert.AreEqual(reminder.TimeFromNow, TimeSpan.MaxValue);
            Assert.IsFalse(reminder.HasStarted);
            Assert.IsFalse(reminder.HasExpired);

            /* Three param Constructor Option */
            const string DAILY = "Daily reminder";
            var reminder1 = new Reminder(DAILY, TOMORROW, emptyDuration);
            var reminder2 = new Reminder(DAILY, TOMORROW, emptyDuration);

            /* Assert Equals and HashCode */
            Assert.AreEqual(reminder1, reminder2);
            Assert.AreEqual(reminder1.GetHashCode(), reminder2.GetHashCode());
        }

        [TestMethod]
        public void StartNow_WithEmptyDuration_StartsAndExpires()
        {
            TimeSpan emptyDuration = new TimeSpan(0);
            var newEmptyReminder = new Reminder(emptyDuration);
            newEmptyReminder.StartNow();
            Assert.IsTrue(newEmptyReminder.HasStarted);
            Assert.AreEqual(newEmptyReminder.TimeFromNow, TimeSpan.Zero);
            Assert.IsTrue(newEmptyReminder.HasExpired);
        }

        [TestMethod]
        public void StartNow_StartsImmediately_ExpiresOnlyAfterDurationSpecified()
        {
            TimeSpan duration = TimeSpan.FromMinutes(1);
            var newReminder = new Reminder(duration);
            newReminder.StartNow();
            Assert.IsTrue(newReminder.HasStarted);
            Assert.AreEqual(newReminder.TimeFromNow.Minutes, TimeSpan.FromMinutes(1).Minutes);
            Assert.IsFalse(newReminder.HasExpired);
        }

        [TestMethod]
        public void StartAt_InFuture_WithDuration_StartsAfterSpecifiedTime()
        {
            TimeSpan duration = TimeSpan.FromSeconds(10);

            var startdt = DateTime.Now + TimeSpan.FromSeconds(10);
            var newReminder = new Reminder(duration);
            newReminder.StartAt(startdt);
            Assert.IsFalse(newReminder.HasStarted);
            Assert.AreEqual(newReminder.TimeFromNow, TimeSpan.MaxValue);
            Assert.IsFalse(newReminder.HasExpired);

            System.Threading.Thread.Sleep(10 * 1000);
            Assert.IsTrue(newReminder.HasStarted);
            var time = newReminder.TimeFromNow.Seconds;
            Assert.IsTrue(time <= 10 & time >= 9);
            Assert.IsFalse(newReminder.HasExpired);

            System.Threading.Thread.Sleep(10 * 1000);
            Assert.IsTrue(newReminder.HasStarted);
            time = newReminder.TimeFromNow.Seconds;
            Assert.AreEqual(time, 0);
            Assert.IsTrue(newReminder.HasExpired);
        }

        [TestMethod]
        public void StartAt_WithNegativeArgument_StartsImmediately()
        {
            TimeSpan duration = TimeSpan.FromSeconds(20);
            var newReminder = new Reminder(duration);

            var startdt = DateTime.Now + TimeSpan.FromSeconds(-10);
            newReminder.StartAt(startdt);
            Assert.IsTrue(newReminder.HasStarted);
            var time = newReminder.TimeFromNow.Seconds;
            Assert.IsTrue(time <= 10 & time >= 9);
            Assert.IsFalse(newReminder.HasExpired);

            var nextReminder = new Reminder(duration);
            startdt += TimeSpan.FromSeconds(-20);
            nextReminder.StartAt(startdt); //End time is in past. Should Expire at Start.

            Assert.IsTrue(nextReminder.HasStarted);
            time = nextReminder.TimeFromNow.Seconds;
            Assert.IsTrue(time >= -10 & time <= -9);
            Assert.IsTrue(nextReminder.HasExpired);
        }
    }
}
